<?php
/**
 * This file is part of the Agora distribution. 
 * Detailed copyright and licensing information can be found
 * in the gpl-3.0.txt file which should be included in the distribution.
 * 
 * @version		$Id: 3.0.14 Olympus 2010-09-28 rammstein4o $
 * @copyright  2007 - 2010 jVitals
 * @license   GPLv3 Open Source
 * @link       http://jvitals.com
 * @since      File available since initial release
 */
 
class AgoraInstaller
{
	function AgoraInstaller()
	{
		$this->__construct();
	}

	function __construct()
	{
		$this->db = & JFactory::getDBO();
		$this->db->debug(0);
		$this->logList = array();
	}

	function query($q)
	{
		$this->db->setQuery($q);
		$this->db->query();
	}

	function runSQLFile($file)
	{
		$path = JPath::clean(JPATH_ADMINISTRATOR.DS."components".DS.'com_agora'.DS.$file);
		$buffer = file_get_contents($path);

		if ( $buffer === false ) {
			$this->log('AgoraInstaller::runSQLFile: '.JText::_('File not found').' '.$file,'error');
//			JError::raiseWarning(1, 'AgoraInstaller::runSQLFile: '.JText::_('File not found').' '.$file);
			return false;
		}

		jimport('joomla.installer.helper');
		$queries = JInstallerHelper::splitSql($buffer);

		if (count($queries) == 0) {
			// No queries to process
			return true;
		}

		// Process each query in the $queries array (split out of sql file).
		foreach ($queries as $query)
		{
			$query = trim($query);
			if ($query != '' && $query{0} != '#') {
				$this->db->setQuery($query);
				if (!$this->db->query()) {
					$this->log('SQL "'.$query.'" failed','notice');
//					JError::raiseWarning(1, 'AgoraInstaller::runSQLFile: '.JText::_('SQL Error').' '.$this->db->stderr(true));
					//return false;
				}
			}
		}
		return count($queries);
	}

	function insert($table, $record)
	{
		$fields = array_map(array($this->db,'nameQuote'),array_keys($record));
		$values = array_map(array($this->db,'Quote'),array_values($record));

		$fields = implode(',',$fields);
		$values = implode(',',$values);

		$query = 'INSERT INTO '.$table.' ('.$fields.') VALUES ('.$values.')';
		$this->db->setQuery($query);
		if (!$this->db->query()) {
			$this->log('SQL "'.$query.'" failed','notice');
//			JError::raiseWarning(1, 'AgoraInstaller::insert(): '.JText::_('SQL Error').' '.$this->db->stderr(true));
			return -1;
		}
		return $this->db->insertid();
	}

	function old()
	{
		$this->log('This version of Agora is too old for automatic upgrade','error');
		return false;
	}

	function pantheon()
	{
		$this->log('Upgrading Agora Pantheon');
		$this->db->setQuery('SELECT * FROM #__agora_groups WHERE g_id NOT IN (1,2,3,4)');
		$old_groups = $this->db->loadAssocList();
		if (!$old_groups) {
			$old_groups = array();
		}

		$this->log('Found '.count($old_groups).' old user groups');
		$new_groups = array();
		foreach ($old_groups as $group) {
			$new_groups[] = array(
				'id'			=> $group['g_id'],
				'name'			=> $group['g_title'],
				'parent_id'		=> 0,
				'caps_message'	=> 1,
				'caps_subject'	=> 1,
				'sig_smilies'	=> 1,
				'sig_bbcode'	=> 1,
				'sig_bbcode_img'=> 1,
				'sig_caps'		=> 1,
				'sig_length'	=> 400,
				'sig_lines'		=> 4,
				'search'		=> $group['g_search'],
				'search_users'	=> $group['g_search_users'],
				'pm'			=> $group['g_pm'],
				'pm_limit'		=> $group['g_pm_limit'],
				//'rep'			=> $group['g_rep_enabled'],
				'rep_minus_min'	=> $group['g_rep_minus_min'],
				'rep_plus_min'	=> $group['g_rep_plus_min'],
				'access'		=> array (
				'read'			=> $group['g_read_board'],
				'bbcode'		=> 1,
				'bbcode_img'	=> 1,
				'read_rss'		=> $group['g_rss_enabled'],
				'post_reply'	=> $group['g_post_replies'],
				'post_poll'		=> $group['g_post_polls'],
				'post_topic'	=> $group['g_post_topics'],
				'delete_topics' => $group['g_delete_topics'],
				'delete_posts'	=> $group['g_delete_posts'],
				'use_captcha'	=> 0,
				)
			);
		}

		$this->db->setQuery('SELECT id, group_id FROM #__agora_users');
		$old_users = $this->db->loadAssocList();
		$user_group = array();
		foreach ($old_users as $user) {
			if ($user['group_id'] == 1) {
				$grp = 1;
				$role = 4;
			} elseif ($user['group_id'] == 2) {
				$grp = 1;
				$role = 3;
			} elseif ($user['group_id'] == 3) {
				$grp = 1;
				$role = 1;
			} elseif ($user['group_id'] == 4) {
				$grp = 1;
				$role = 2;
			} else {
				$grp = $user['group_id'];
				$role = 2;
			}

			$user_group[] = array (
				'user_id' => $user['id'],
				'group_id' => $grp,
				'role_id' => $role,
			);
		}

		$this->db->setQuery('SELECT * FROM #__agora_forum_perms');
		$perms = $this->db->loadAssocList();
		if (!$perms) {
			$perms = array();
		}

		$group_forum = array();
		foreach ($perms as $perm) {
			$dup = false;
			if ($perm['group_id'] == 1) {
				$grp = 1;
				$role = 4;
			} elseif ($perm['group_id'] == 2) {
				$grp = 1;
				$role = 3;
			} elseif ($perm['group_id'] == 3) {
				$grp = 1;
				$role = 1;
			} elseif ($perm['group_id'] == 4) {
				$grp = 1;
				$role = 2;
			} else {
				$grp = $perm['group_id'];
				$role = 1;
				$dup = true;
			}

			$new_group_forum = array (
				'forum_id'	=> $perm['forum_id'],
				'group_id'	=> $grp,
				'role_id'	=> $role,

				'access'	=> array (
				'read'			=> $perm['read_forum'],
				'bbcode'		=> 1,
				'bbcode_img'	=> 1,
				'read_rss'		=> $perm['rss_enabled'],
				'post_reply'	=> $perm['post_replies'],
				'post_poll'		=> $perm['post_polls'],
				'post_topic'	=> $perm['post_topics'],
				'delete_topics' => 1,
				'delete_posts'	=> 1,
				'use_captcha'	=> 0,
				),
			);
			$group_forum[] = $new_group_forum;
			if ($dup) {
				for ($i = 2; $i <= 4; $i++) {
					$new_group_forum['role_id'] = $i;
					$group_forum[] = $new_group_forum;
				}
			}
		}

		$this->db->setQuery('SELECT * FROM jos_agora_Ratings');
		$ratings = $this->db->loadAssocList();

/*		$this->db->setQuery('SELECT id FROM #__agora_forums');
		$forums = $this->db->loadAssocList();
		foreach ($forums as $forum_id) {

			$new_group_forum = array (
				'forum_id'	=> $forum_id,
				'group_id'	=> 1,

				'access'	=> array (
					'read'			=> $perm['read_forum'],
					'bbcode'		=> 1,
					'bbcode_img'	=> 1,
					'read_rss'		=> $perm['rss_enabled'],
					'post_reply'	=> $perm['post_replies'],
					'post_poll'		=> $perm['post_polls'],
					'post_topic'	=> $perm['post_topics'],
					'delete_topics' => 1,
					'delete_posts'	=> 1,
					'use_captcha'	=> 1,
				)
			);
			for ($role=1; $role <= 4; $role+=1) {
				$new_group_forum['role_id'] = $role;
				if ($role == 1) {
					//guest
					$new_group_forum['access']['post_reply'] = 0;
					$new_group_forum['access']['post_poll'] = 0;
					$new_group_forum['access']['post_topic'] = 0;
					$new_group_forum['access']['delete_topics'] = 0;
					$new_group_forum['access']['delete_posts'] = 0;
				} elseif ($role == 2) {
					//member
					$new_group_forum['access']['post_reply'] = 1;
					$new_group_forum['access']['post_poll'] = 1;
					$new_group_forum['access']['post_topic'] = 1;
					$new_group_forum['access']['delete_topics'] = 0;
					$new_group_forum['access']['delete_posts'] = 0;
				} else {
					//admin-moder
					$new_group_forum['access']['post_reply'] = 1;
					$new_group_forum['access']['post_poll'] = 1;
					$new_group_forum['access']['post_topic'] = 1;
					$new_group_forum['access']['delete_topics'] = 1;
					$new_group_forum['access']['delete_posts'] = 1;
				}
				$group_forum[$forum_id] = $new_group_forum;
			}
		}*/

		$this->log('Applying changes in metadata');

		if (!$this->runSQLFile('upgrade.pantheon.sql')) return false;

		$group_ids = array('1' => '1');

		$this->log('Creating groups ('.count($new_groups).' will be created)');

		foreach ($new_groups as $group) {
			$access = $group['access'];
			$old_id = $group['id'];
			unset($group['access']);
			unset($group['id']);

			$perm_guest = $this->insert('#__agora_permissions',$access);
			$perm_member = $this->insert('#__agora_permissions',$access);
			$perm_moder = $this->insert('#__agora_permissions',$access);
			$perm_admin = $this->insert('#__agora_permissions',$access);
			
			$group_ids[$old_id] = $this->insert('#__agora_group',$group);

			$perms = array('group_id'=>$group_ids[$old_id],'role_id'=>'1','access_id'=>$perm_guest);
			$this->insert('#__agora_group_permissions',$perms);

			$perms = array('group_id'=>$group_ids[$old_id],'role_id'=>'2','access_id'=>$perm_member);
			$this->insert('#__agora_group_permissions',$perms);

			$perms = array('group_id'=>$group_ids[$old_id],'role_id'=>'3','access_id'=>$perm_moder);
			$this->insert('#__agora_group_permissions',$perms);

			$perms = array('group_id'=>$group_ids[$old_id],'role_id'=>'4','access_id'=>$perm_admin);
			$this->insert('#__agora_group_permissions',$perms);
		}

		foreach ($user_group as $record) {
			if (!isset($group_ids[$record['group_id']])) continue;

			$record['group_id'] = $group_ids[$record['group_id']];
			$this->insert('#__agora_user_group',$record);
		}

		foreach ($group_forum as $record) {
			if (!isset($group_ids[$record['group_id']])) continue;

			$access = $record['access'];
			unset($record['access']);
			
			$record['access_id'] = $this->insert('#__agora_permissions',$access);
			$record['role_id'] = 1;
			$record['group_id'] = $group_ids[$record['group_id']];
			$this->insert('#__agora_group_forum',$record);

			$record['access_id'] = $this->insert('#__agora_permissions',$access);
			$record['role_id'] = 2;
			$record['group_id'] = $group_ids[$record['group_id']];
			$this->insert('#__agora_group_forum',$record);

			$record['access_id'] = $this->insert('#__agora_permissions',$access);
			$record['role_id'] = 3;
			$record['group_id'] = $group_ids[$record['group_id']];
			$this->insert('#__agora_group_forum',$record);

			$record['access_id'] = $this->insert('#__agora_permissions',$access);
			$record['role_id'] = 4;
			$record['group_id'] = $group_ids[$record['group_id']];
			$this->insert('#__agora_group_forum',$record);
		}

		foreach ($ratings as $record) {
			$this->insert('#__agora_ratings',$record);
		}

		return true;

	}

	function log($mess,$type='info')
	{
		$entry = new stdClass();
		$entry->message = $mess;
		$entry->type = $type;
		$this->logList[] = $entry;
	}

	function olympus()
	{
		$this->log('Upgrading previous Agora Olympus installation');
		
		$path = JPath::clean(JPATH_ADMINISTRATOR.DS."components".DS.'com_agora'.DS.'upgrade.php');
		include_once($path);
		$upgrader = new AgoraDatabaseUpgrade();

		$old_debug = $this->db->_debug;
		$this->db->debug(0);
		$this->db->setQuery('SELECT conf_value FROM #__agora_config WHERE conf_name = \'o_database_revision\'');
		$current_revision = $this->db->loadResult();
		$this->log('Detected database metadata revision: '.intval($current_revision));
		
		$sts = $upgrader->getStatements($current_revision);

		foreach ($sts as $st) {
			if (method_exists($upgrader, $st)) {
				$upgrader->$st($this->db);
				continue;
			}
			
			$this->db->setQuery($st);
			$this->db->query();
		}
		$this->db->debug($old_debug);
		return true;
	}

	function fresh()
	{
		$this->log('Performing fresh installation');
		return $this->runSQLFile('upgrade.fresh.sql');		
		
	}
	
	function joopport()// new in joopport 0.2
	{
	
		$this->log('Performing fresh installation of Joopport'); // new in joopport 0.2
		return $this->runSQLFile('upgrade.joopport.sql'); // new in joopport 0.2
	
	
	}	

	function checkMixedCollations() {
		
		// for now we suspend collation checking untill better times
		// TODO - add database name as prefix to table so we collect information only from the current database !!!
		return 1;
		
		/*
		$query1 = 'SELECT DISTINCT table_collation FROM INFORMATION_SCHEMA.TABLES WHERE table_name LIKE \'%agora_%\'';
		$query2 = 'SELECT DISTINCT collation_name FROM information_schema.columns WHERE table_name LIKE \'%agora_%\' AND collation_name IS NOT NULL;';
		
		$this->db->setQuery($query1);
		$result_tables = $this->db->loadResultArray();
		
		$this->db->setQuery($query2);
		$result_columns = $this->db->loadResultArray();
		
		$table_count = (is_array($result_tables) && count($result_tables) > 0) ? (int)count($result_tables) : 0;
		$column_count = (is_array($result_columns) && count($result_columns) > 0) ? (int)count($result_columns) : 0;
		
		if ( ($table_count > 1) || ($column_count > 1) || ($table_count == 1 && $column_count == 1 && $result_columns[0] != $result_tables[0])) {
			return -1;
		} elseif ($table_count == 0 || $column_count == 0) {
			return -2;
		} else {
			return 1;
		}
		*/

		$q_jusers = 'SELECT DISTINCT table_collation FROM INFORMATION_SCHEMA.TABLES WHERE table_name = \'' . $db->_table_prefix . 'users\'';
		$q_ausers = 'SELECT DISTINCT table_collation FROM INFORMATION_SCHEMA.TABLES WHERE table_name = \'' . $db->_table_prefix . 'agora_users\'';
		$q_agora = 'SELECT DISTINCT table_collation FROM INFORMATION_SCHEMA.TABLES WHERE table_name LIKE \'' . $db->_table_prefix . 'agora%\' AND table_name <> \'' . $db->_table_prefix . 'agora_users\'';

		$this->db->setQuery($q_jusers);
		$jusers = $this->db->loadResultArray();
		
		$this->db->setQuery($q_ausers);
		$ausers = $this->db->loadResultArray();
		
		$this->db->setQuery($q_agora);
		$agora = $this->db->loadResultArray();
		
		$count_jusers = (is_array($jusers) && count($jusers) > 0) ? (int)count($jusers) : 0;
		$count_ausers = (is_array($ausers) && count($ausers) > 0) ? (int)count($ausers) : 0;
		$count_agora = (is_array($agora) && count($agora) > 0) ? (int)count($agora) : 0;
		
		if ($count_jusers == 0 || $count_ausers == 0 || $count_agora == 0) {
			return -1;
		} elseif ($jusers[0] != $ausers[0]) {
			return -2;
		} elseif ($count_agora > 1) {
			return -3;
		} elseif ($ausers[0] != $agora[0]) {
			return -4;
		} else {
			return 1;
		}
		
	}

	function run()
	{
		$result = null;
		$collations = $this->checkMixedCollations();
		
		if ($collations == -1) {
		
			$this->log('Error while getting table and column collations, installer cannot continue. Please examine the database and send this log to Agora support team.', 'error');
			
		} elseif ($collations == -2) {
		
			$this->log('Installer detected that the collations of Joomla Users table and Agora Users table do not match. Please send this log to Agora support team and fix this issue before installing Agora.', 'error');
			
		} elseif ($collations == -3) {
		
			$this->log('Installer detected that there are Agora tables with mixed collation. Please examine the database and send this log to Agora support team.', 'error');
			
		} elseif ($collations == -4) {
		
			$this->log('Installer detected that the collation of Agora Users table differs from the collation of the rest of the Agora tables. Please examine the database and send this log to Agora support team.', 'error');
			
		} else {
		
			$this->db->setQuery('SELECT conf_value FROM #__agora_config WHERE conf_name=\'o_cur_version\'');
			$old_version = $this->db->loadResult();
			
			$this->log('Detecting old version: '.htmlentities($old_version));

			if (is_null($old_version)) {
				$result = $this->fresh();
				$result_joopport = $this->joopport(); // new in joopport 0.2
			} elseif (strpos($old_version,'3.0.') !== FALSE) {
				$result = $this->olympus();
			} elseif (strpos($old_version,'2.5.') !== FALSE) {
				$result = $this->pantheon();
			} else {
				$result = $this->old();
			}

			if ($result) {
				$this->log('Complete');
			} else {
				$this->log('Serious error detected. Installer failed and cannot continue');
				$this->log('Please send this log to Agora support team');
			}
			
			if (!$result_joopport)  // new in joopport 0.2
			{
				$this->log('Serious error detected. Installer can not install Joopport. SQL error.');
			}
			
		}
		return $result;
	}

	function display()
	{
		$doc = & JFactory::getDocument();
		$doc->addScript(JURI::base().'components/com_agora/js/service.js');
		
		?>
		<div style="width: 100%">
			<div style="width: 35%; float: left">
			<fieldset>
				<legend>Installer actions</legend>
				<a href="javascript:void(0)" onClick="ag_checkDirs()">Check directory permissions</a>
				<br/><br/>
				<a href="javascript:void(0)" onClick="ag_syncUsers()">Syncronise Joomla<->Agora users</a>
				<br/><br/>
				<a href="javascript:void(0)" onClick="ag_installClean('WARNING! This will unconditionally destroy ALL agora tables. Are you sure?')">Install clean database</a>
				<br/><br/>
				<a href="javascript:void(0)" onClick="$('agora_log').empty()">Clear log</a>
			</fieldset>
			</div>
			<div style="font-size : 120%; width: 63%; float: left; margin-left: 2%;">
			<fieldset>
				<legend>Installer log</legend>
				<div id="agora_log" style="overflow: auto; max-height: 300px">
					<h2>Performed operations</h2>
				<?php
					foreach ($this->logList as $logs) {
						switch ($logs->type) {
							case 'error': $color = '#FF0000'; break;
							case 'info': $color = '#0000FF'; break;
							default: $color = '#000000';
						}
						echo '<span color="'.$color.'">'.$logs->message.'</span><br/>'."\n";
					}
				?>
				</div>
			</fieldset>
			</div>
		</div>
		<script type="text/javascript">
			ag_checkDirs();
			ag_syncUsers();
		</script>
		<?php
	}
	
	// Auti install plugins in admin/plugins

	function getPluginName($dir) {
		jimport('joomla.filesystem.folder');
		jimport('joomla.filesystem.file');
		$name = '';
		
		// Search the install dir for an xml file
		$files = JFolder::files($dir, '\.xml$', 1, true);
		if (count($files) > 0) {
			foreach ($files as $file) {
				$name = '';
				$xml = JFactory::getXMLParser('Simple');
				$xml->loadFile($file);
				$children = $xml->document->_children;
				foreach ($children as $child) {
					if ($child->_name == 'name') {
						$name = JFilterInput::clean($child->_data, 'string');
						break;
					}
				}
				$xml = null;
				if (!$name) {
					continue;
				}
				return $name;
			}
		}
		return $name;
	}

	function enablePlugin($type, $name) {
		if ($type == 'plugin') {
			$this->db->setQuery("UPDATE #__plugins SET " . $this->db->nameQuote('published') . " = '1' WHERE " . $this->db->nameQuote('name') . " = " . $this->db->Quote($name));
			$this->db->query();
		}
	}

	function installPlugins() {
		jimport('joomla.filesystem.archive');
		jimport('joomla.installer.installer');
		jimport('joomla.installer.helper');
		
		$allowed_extensions = 'zip,rar,gz,bz2';
		
		$componentInstaller =& JInstaller::getInstance();
		$source = $componentInstaller->getPath('source') . DS . 'admin' . DS . 'plugins' . DS;
		
		if (is_dir($source)) {
			if ($dh = opendir($source)) {
				while (($file = readdir($dh)) !== false) {
					if ($file != '.' && $file != '..') {
						$pathInfo = pathinfo($source . $file);
						$ext = isset($pathInfo['extension']) && $pathInfo['extension'] ? (string)$pathInfo['extension'] : '';
						
						if ($ext && in_array($ext, explode(',', $allowed_extensions))) {
						
							$installer = new JInstaller();
							$package = JInstallerHelper::unpack($source . $file);
							
							if(!$installer->install($package['dir'])) {
								$this->log('Error installing plugin ' . $source . $file, 'error');
							} else {
								$name = $this->getPluginName($package['extractdir']);
								$this->enablePlugin($package['type'], $name);
								// Cleanup the install files
								if (!is_file($package['packagefile'])) {
									$package['packagefile'] = $source . $package['packagefile'];
								}
								JInstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
								$this->log('Plugin ' . $name . ' successfully installed.');
							}
						} else {
							$this->log('Plugin archive extension (' . $ext . ') is not in the allowed list (' . $allowed_extensions . ')', 'error');
						}
					}
				}
				closedir($dh);
			} else {
				$this->log('Cannot open directory ' . $source . ' (should containt plugins).', 'error');
			}
		} else {
			//$this->log('Directory ' . $source . ' (should containt plugins) does not exist.', 'error');
		}
	}
	
}

function com_install() {
	$installer = new AgoraInstaller();
	$installer->run();
	$installer->installPlugins();
	$installer->display();
}

?>